package com.xbts.screen.monitor.domain.request;

import com.xbts.screen.monitor.domain.response.GetTokenResponse;
import com.xbts.screen.monitor.domain.schedule.UpdateTokenSchedule;
import com.xbts.screen.monitor.domain.token.*;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * 请求基类
 */
@Data
@Component
public abstract class BaseRequest<T> {
    public static final Logger logger = LoggerFactory.getLogger(BaseRequest.class);

    //客户端信息
    private OauthConfigBaseInfo oauthConfigBaseInfo;
    //请求方式
    private String method;
    //请求url
    private String url;
    //请求头
    private Map<String, String> header = new HashMap<String, String>();
    //请求体
    protected String body;
    //支持常见的form表单类型：application/x-www-form-urlencoded；multipart/form-data
    protected Map<String, Object> form;
    //是否需要鉴权,默认需要
    private boolean needAuth = true;

    private TokenStore tokenStore = UpdateTokenSchedule.tokenStore;

    public abstract T doAction();

    public BaseRequest(){}

    public BaseRequest(OauthConfigBaseInfo oauthConfigBaseInfo, String method, String url, boolean needAuth){
        this.oauthConfigBaseInfo = oauthConfigBaseInfo;
        this.method = method;
        this.url = url;
        this.needAuth = needAuth;
        this.header();
        //TODO：暂时不开启刷新token任务
        //UpdateTokenSchedule.getInstance();
    }

    public void header(){
       //从缓存获取access_token
        if(this.needAuth){
            Token token = getToken();
            if(token == null)return;
            header.put("Authorization", "bearer " + (token != null ? token.getAccess_token() : ""));
            if(GrantType.password == oauthConfigBaseInfo.getGrantType()){
                header.put("User-Id", (token != null ? token.getUserId() : "1"));
            }
        }
    }

    public Token getToken(){
        Token token = null;
        if(tokenStore instanceof LocalTokenStore){
            LocalTokenStore localTokenStore = (LocalTokenStore)tokenStore;
            Map<String, Token> tokenMap = localTokenStore.getTokenMap();
            String key = UpdateTokenSchedule.getKey(this.oauthConfigBaseInfo);
            if(!CollectionUtils.isEmpty(tokenMap)){
                token = tokenMap.get(key);
                if(token != null){
                    //token是否过期，过期则删除,重新获取
                    if(System.currentTimeMillis() / 1000 >= token.getTtl()){
                        tokenMap.remove(key);
                    }else{
                        logger.info("Get token from Local Story Cache...");
                        return token;
                    }
                }
                //掉接口获取token
                token = getTokenFromRemote();
                if(token != null){
                    //缓存token到本地
                    tokenMap.put(key, token);
                }
            }else {
                //掉接口获取token
                token = getTokenFromRemote();
                if(token != null){
                    //缓存token到本地
                    tokenMap.put(key, token);
                }
            }
        }
        if(tokenStore instanceof MysqlTokenStore){
            MysqlTokenStore mysqlTokenStore = (MysqlTokenStore)tokenStore;
            Map<String, Token> tokens =  mysqlTokenStore.getToken();
            String key = UpdateTokenSchedule.getKey(this.oauthConfigBaseInfo);
            if(!CollectionUtils.isEmpty(tokens)){
                token = tokens.get(key);
                if (token != null){
                    //token是否过期，过期则删除,重新获取
                    if(System.currentTimeMillis() / 1000 >= token.getTtl()){
                        tokens.remove(key);
                    }else{
                        logger.info("Get token from Mysql Cache...");
                        return token;
                    }
                }
                //掉接口获取token
                token = getTokenFromRemote();
                if(token != null){
                    //缓存token到Mysql
                    mysqlTokenStore.tokenStore(key, token);
                }
            }else {
                //掉接口获取token
                token = getTokenFromRemote();
                if(token != null){
                    //缓存token到Mysql
                    mysqlTokenStore.tokenStore(key, token);
                }
            }
        }
        if(tokenStore instanceof RedisTokenStore){
            RedisTokenStore redisTokenStore = (RedisTokenStore)tokenStore;
            Map<String, Token> tokens = redisTokenStore.getToken();
            String key = UpdateTokenSchedule.getKey(this.oauthConfigBaseInfo);
            if(!CollectionUtils.isEmpty(tokens)){
                token = tokens.get(key);
                if(token != null){
                    //token是否过期，过期则删除,重新获取
                    if(System.currentTimeMillis() / 1000 >= token.getTtl()){
                        tokens.remove(key);
                    }else{
                        logger.info("Get token from Redis Cache...");
                        return token;
                    }
                }
                //掉接口获取token
                token = getTokenFromRemote();
                //缓存token到Redis
                if(token != null){
                    redisTokenStore.tokenStore(key, token);
                }
            }else{
                //掉接口获取token
                token = getTokenFromRemote();
                if(token != null){
                    //缓存token到Redis
                    redisTokenStore.tokenStore(key, token);
                }
            }

        }
        return token;
    }

    public Token getTokenFromRemote(){
        logger.info("Get token from remote...");
        //获取公钥
        GetTokenRequest request = new GetTokenRequest(oauthConfigBaseInfo);
        GetTokenResponse getTokenResponse = request.doAction();
        if(!getTokenResponse.isSuccess()){
            logger.error("BaseRequest,getTokenFromRemote,get token error,error msg:{}",getTokenResponse.getErrMsg());
            return null;
        }
        Token token = getTokenResponse.getData();
        //设置ttl
        token.setTtl(token.getExpires_in() + System.currentTimeMillis() / 1000);
        return token;
    }
}
